﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.IO;
using Game.Klassen;
using System.Media;
using Game.Frames;
using Game.Classes;
using System.Drawing.Text;


namespace Game
{
    class Session
    {
        //Statische Klasse um manche Abläufe besser zu organisieren
        //Tileset erstellen und verschiedene Variablen für die Frames
        public static Tileset   tileset = new Tileset();
        public static Editor    frmEditor;
        public static Form      frmModal;
        public static Main      fenster;
        public static bool      soundEnabled = true;

        //Allgemeines
        public static Random rand = new Random();

        //Liste für Objekte
        public static List<BackGroundObject>    bgObjects   = new List<BackGroundObject>();
        public static List<ForeGroundObject>    fgObjects   = new List<ForeGroundObject>();

        //Spieler erstellen
        public static List<Player> players = new List<Player>()
        {
            new Player("Spieler 1", 5, new Point(2, 3), Game.Properties.Resources.player1_move, Game.Properties.Resources.player1_stand)
        };
        
        //Aktiven Spieler setzen
        public static Player    currentPlayer;
        public static int       currentPlayerIndex;
        public static string    state = "loading";


        //Schriftarten laden
        public static PrivateFontCollection customFont = new PrivateFontCollection();
        public static FontFamily            fontFam;

        public static Font bigFont;
        public static Font buttonFont;
        public static Font smallFont;
        public static Font tinyFont;

        //Timer für Nachrichten
        public static Timer     hideMessage = new Timer();
        public static string    infoMessage = String.Empty;

        #region Default Map
        public static string[][] bgmap = new string[][]{
                new string[]{"0", "0", "0", "0", "0", "0", "104", "105", "100", "103", "0", "0", "0", "0", "0","0"},
                new string[]{"0", "0", "0", "0", "0", "0", "105", "0", "100", "106", "0", "0", "0", "0", "0","0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "105", "0", "0", "0", "0", "0", "0","0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0","0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0","0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "101", "0", "101", "0","0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "101", "0", "0","0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "104", "100", "103", "0","0"},
                new string[]{"0", "101", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "105", "0", "0","0"},
                new string[]{"104", "100", "101", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0","0"},
                new string[]{"104", "100", "102", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0","0"},
                new string[]{"104", "100", "100", "101", "103", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0","0"}
        };



        public static string[][] map = new string[][]{
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "1", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "2", "3", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "2", "3", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"},
                new string[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"}
            };
        #endregion

        #region Tools
        //Pos is Empty
        public static bool isEmpty(Point pos)
        {
            bool empty = true;

            if (!map[pos.Y][pos.X].StartsWith("0"))
                empty = false;

            foreach (BackGroundObject obj in bgObjects)
                if (obj.position == pos)
                    empty = false;

            foreach (Player p in players)
                if (p.pos == pos)
                    empty = false;

            return empty;
        }

        //Nachricht auf dem Bildschirm anzeigen
        public static void setMessage(string message)
        {
            Session.infoMessage = message;
            Session.hideMessage.Stop();
            Session.hideMessage.Start();
        }

        //Neue Powerups Spawnen
        public static void chanceToAddNewPowerup()
        {
            if (Session.currentPlayer.turns > 1)
            {
                int randPowerup = Session.rand.Next(1, 8);

                if (randPowerup < 3)
                    addPowerUp("o2");
                else if (randPowerup == 4)
                    addPowerUp("co2");
                else if (randPowerup == 5)
                    addPowerUp("whirl");
                else if (randPowerup == 6)
                    addPowerUp("he");
                else if (randPowerup == 7)
                    addPowerUp("plant");
            }
        }

        //Powerup Sauerstoffflasche platzieren
        public static void addPowerUp(string type)
        {
            int height = Session.map.Length;
            int width = Session.map[0].Length;

            int randX = Session.rand.Next(0, width);
            int randY = Session.rand.Next(0, height);
            int timeout = 0;

            while (!isEmpty(new Point(randX, randY)) && timeout < 100)
            {
                randX = Session.rand.Next(0, width);
                randY = Session.rand.Next(0, height);
                timeout++;
            }

            if (timeout < 100)
            {
                if (type == "o2")
                    bgObjects.Add(new OxygenTank(new Point(randX, randY), new Size(60, 60)));
                else if (type == "co2")
                    bgObjects.Add(new CO2Tank(new Point(randX, randY), new Size(60, 60)));
                else if (type == "whirl")
                    bgObjects.Add(new Whirl(new Point(randX, randY), new Size(60, 60)));
                else if (type == "he")
                    bgObjects.Add(new HeTank(new Point(randX, randY), new Size(60, 60)));
                else if (type == "plant")
                    bgObjects.Add(new Plant(new Point(randX, randY), new Size(60, 60)));
            }
            
        }

        //Neuen Schlüssel platzieren
        public static void placeNewKey()
        {
            int height  = Session.map.Length;
            int width   = Session.map[0].Length;

            int start = height - height / 10;
            int kY = 0;

            if (height - 2 >= start)
                kY = Session.rand.Next(start, height - 2);
            else
                kY = height-1;
            int kX = Session.rand.Next(1, width - 1);

            int timeout = 0;

            while (!isEmpty(new Point(kX, kY)) && timeout < 100)
            {
                kY = Session.rand.Next(start, height);
                kX = Session.rand.Next(1, width - 1);
                timeout++;
            }
            
            if (timeout < 100)
                bgObjects.Add(new Key(new Point(kX, kY), new Size(40, 40)));
        }

        //Karte aus Datei laden
        public static void loadMapFromFile(string path)
        {
            //Rendering Pausieren
            state = "loading";

            //Zeilen aus der Map Datei lesen
            string[] lines = File.ReadAllLines(path);

            //ConfigZeile und PositionsZeile Splitten
            string[] config     = lines[0].Split(';');
            string[] positions  = lines[1].Split(';');
            int      playerCount= int.Parse(config[0]);

            //Spielerliste/Hintergrundobjekte leeren und neue erstellen
            players.Clear();
            for(int p = 0; p < playerCount; p++)
            {
                //Spielerposition lesen
                String[] pos = positions[p].Split(':');

                Image standImg  = Tools.getPlayerStandImage(p);
                Image moveImg   = Tools.getPlayerMoveImage(p);

                //Prüfen ob Spielerpositionen gesetzt wurden.. Wennn nicht Pos(1,1)
                int pX = int.Parse(pos[0]) > 0 ? int.Parse(pos[0]) : 1;
                int pY = int.Parse(pos[1]) > 0 ? int.Parse(pos[1]) : 1;

                //Spieler hinzufügen
                players.Add(new Player("Spieler "+(p+1), 5, new Point(pX, pY), moveImg, standImg));
            }

            //Aktuellen Spieler setzen
            currentPlayer       = players[0];
            currentPlayerIndex  = 0;

            //Map Dimensionen lesen
            int width = int.Parse(config[1]);
            int height = int.Parse(config[2]);

            //Map erstellen und aus Datei laden
            map = new string[height][];
            for (int i = 0; i < height; i++)
            {
                map[i] = new string[width];
                for (int x = 0; x < width; x++)
                {
                    string[] ids = lines[2+i].Split(';');
                    map[i][x] = ids[x];
                }
            }

            //Hintergrundmap erstellen und aus Datei laden
            bgmap = new string[12][];
            for (int i = 0; i < 12; i++)
            {
                bgmap[i] = new string[16];
                for (int x = 0; x < 16; x++)
                {
                    string[] ids = lines[2+height+i].Split(';');
                    bgmap[i][x] = ids[x];
                }
            }

            //Hintergrundobjekte neu initialisieren
            bgObjects.Clear();

            //1 Schlüssel für jeden Spieler auf der Map platzieren
            for (int x = 0; x < playerCount; x++)
            {
                placeNewKey();
            }

            //Fischschwärme einfügen
            int fishcount = Convert.ToInt32((width * height) * 0.015);
            for (int x = 0; x < fishcount; x++)
            {
                int randX = Session.rand.Next(0, width);
                int randY = Session.rand.Next(0, height);

                while (!map[randY][randX].StartsWith("0"))
                {
                    randX = Session.rand.Next(0, width);
                    randY = Session.rand.Next(0, height);
                }
                bgObjects.Add(new AnimatedObject(new Point(randX, randY), new Size(60, 60)));
            }

            //Positionsunabhängige Objekte hinzufügen
            fgObjects.Clear();
            for (int x = 0; x < 10; x++)
            {
                int size = rand.Next(50, 80);
                fgObjects.Add(new FGBubble(new Point(rand.Next(0, 1024), rand.Next(0, 768)), new Size(size, size)));
            }

            //Truhe Hinzufügen
            int cX = int.Parse(config[3]);
            int cY = int.Parse(config[4]);
            bgObjects.Add(new Chest(new Point(cX, cY), new Size(60, 60)));

            state = "play";
        }

        //Bewegungskosten berechnen
        public static int getMoveCost(Point pos)
        {
            //Position des Spielers und  die Größe der Map holen
            int pY = pos.Y;
            int height = Session.map.Count();

            //Falls der Spieler aus irgend einem Grund außerhalb des Feldes steht...
            if (pY < 1)
                pY = 1;

            //Spielerposition prozentual aufs Spielfeld gesehen
            double percentage = ((double)pY / (double)height)*100;

            //Kostenzonen 40%, 30%, 20%, 10%
            if (percentage <= 40)
                return 1;
            else if (percentage < 70)
                return 2;
            else if (percentage < 90)
                return 3;
            else
                return 4;
        }

        //schriftarten init
        public static void loadFont()
        {
            //Font laden
            if (File.Exists("./Files/GhostOfMars.ttf"))
            {
                Session.customFont.AddFontFile("./Files/GhostOfMars.ttf");
                Session.fontFam = customFont.Families[0];

                Session.bigFont     = new Font(fontFam, 48, FontStyle.Bold);
                Session.buttonFont  = new Font(fontFam, 24, FontStyle.Bold);
                Session.smallFont   = new Font(fontFam, 18, FontStyle.Bold);
                Session.tinyFont    = new Font(fontFam, 14, FontStyle.Bold);
            }
            else
                Console.WriteLine("Schrift nicht gefunden -> Fallback default Font");
        }

        //Runde beenden --> Nächster Spieler
        public static void endTurn()
        {
            if (Session.currentPlayer.enabled)
            {
                //Nachricht leeren
                Session.setMessage("");

                //Kampfflag zurücksetzen
                Session.currentPlayer.alreadyFought = false;

                //Spieler 5 Sauerstoff hinzufügen
                Session.currentPlayer.addOxygen(5);

                //Rundenzähler erhöhen
                Session.currentPlayer.turns += 1;

                //Enabled Setzen
                Session.currentPlayer.enabled = true;

                //Nächster Spieler ist am Zug
                int playerCount = Session.players.Count;
                if (Session.currentPlayerIndex + 1 < playerCount)
                {
                    Session.currentPlayerIndex++;
                    Session.currentPlayer = Session.players[Session.currentPlayerIndex];
                }
                else
                {
                    Session.currentPlayerIndex = 0;
                    Session.currentPlayer = Session.players[0];
                }

                Session.setMessage(Session.currentPlayer.name + " ist am Zug.");

                //Chance dass ein Powerup erscheint
                chanceToAddNewPowerup();
            }
            else
                Session.setMessage("Zug noch nicht beendet");
        }
        #endregion

    }
}
